package com.dungeon.game;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import com.dungeon.game.Constants.Character_action_code;
import com.dungeon.game.Constants.Class_code;
import com.dungeon.game.Constants.Equipment_type_code;
import com.dungeon.game.Constants.Potion_type;
import com.dungeon.game.Constants.Scenario_code;

public class Charsheet implements Serializable{
	private static final long serialVersionUID = 6386001409924251160L;
	int level, xp;
	String name;
	Class_code class_code;
	String image;
	int intelligence,stat1,stat2,constitution,stamina,reflexes;
	ArrayList<Potion_type> potions;
	Item armor, offhand, melee_weapon, missile_weapon;
	ArrayList<Item> trinkets;
	ArrayList<Character_action_code> master_action_codes, obsoleted_actions;
	String genesis;

	public Charsheet(Class_code _class_code,String _image,String _name,int _level,int _intelligence,int _stat1,int _stat2,
			int _constitution,int _stamina,int _reflexes,List<Character_action_code> _action_codes,List<Character_action_code> _obsoleted_actions,
			List<Potion_type> _potions,Equipment_type_code _armor,Equipment_type_code _melee_weapon,Equipment_type_code _offhand,
			Equipment_type_code _missile_weapon,Equipment_type_code _trinket1,Equipment_type_code _trinket2,Equipment_type_code _trinket3,String _genesis){
        class_code = _class_code;
        name = _name;
        image = _image;
        level = _level;
        xp = xp_needed_for_level(level);
        stat1 = _stat1; // Str Val Dar Pow
        stat2 = _stat2; // Ski Wis Cun Sub
        intelligence = _intelligence;
        constitution = _constitution;
        stamina = _stamina;
        reflexes = _reflexes;
        master_action_codes = new ArrayList(_action_codes);
        obsoleted_actions = new ArrayList(_obsoleted_actions);
        potions = new ArrayList(_potions);
        melee_weapon = Campaignstate.i.make_item(_melee_weapon);
        missile_weapon = Campaignstate.i.make_item(_missile_weapon);
        offhand = Campaignstate.i.make_item(_offhand);
        armor = Campaignstate.i.make_item(_armor);
        trinkets = new ArrayList<Item>();
        if (_trinket1!=null){
            trinkets.add(Campaignstate.i.make_item(_trinket1));
        }
        if (_trinket2!=null){
            trinkets.add(Campaignstate.i.make_item(_trinket2));
        }
        if (_trinket3!=null){
            trinkets.add(Campaignstate.i.make_item(_trinket3));
        }
        genesis = _genesis;
    }

	static int percent_progress_lost_on_death_by_level(int level){
		List<Integer> percents = Arrays.asList(0,0,0,0,5,5,10,10,10,10,10);
		return percents.get(level);
	}

	static int xp_needed_for_level(int level){
		List<Integer> reqs = Arrays.asList(0,50,150,500,1500,5000,15000,50000,150000,250000,350000,999999);
		return reqs.get(level);
	}

	int respec_cost(){
		List<Integer> reqs = Arrays.asList(0,5,5,10,25,50,200,500,500,500,500);
		int result = reqs.get(level);
		if (Campaignstate.victories.contains(Scenario_code.SC_DESERT)) result = (result*2)/5;
		return result;
	}

	ArrayList<Integer> make_progression(int base,int first_increment_at,int next_gap,int following_gap){
	    ArrayList<Integer> progression = new ArrayList<Integer>();
	    for (int i=0; i<base; i++){
	        progression.add(1);
	    }
	    progression.add(first_increment_at);
	    if (next_gap + following_gap > 0){
	    	int max = -1;
	    	for (int i=0; i<progression.size(); i++){
	    		max = Math.max(max,progression.get(i));
	    	}
	        while (max<=20){
	            progression.add(max+next_gap);
	            progression.add(max+next_gap+following_gap);
	        	max = -1;
		    	for (int i=0; i<progression.size(); i++){
		    		max = Math.max(max,progression.get(i));
		    	}
	        }
	    }
	    return progression;
	}

	int value(int x, List<Integer> progression){
	    int val = 0;
	    for (Integer i : progression){
	        if (x >= i){
	            val = val + 1;
	        }
	    }
	    return val;
	}

	List<Character_action_code> get_action_codes(){
		ArrayList<Character_action_code> action_codes = new ArrayList<Character_action_code>();
        for (Character_action_code a : master_action_codes){
            if (action_codes.size() < (get_n_skills()-obsoleted_actions.size()))
                action_codes.add(a);
        }
        for (Item item : all_carried()){
            if (item!=null){
                for (Character_action_code a : item.action_codes()){
                    if (!action_codes.contains(a))
                        action_codes.add(a);
                }
            }
        }
		return action_codes;
	}

	boolean fire_melee(){
        for (Item item : all_carried())
            if (item!=null)
                if (item.fire_melee())
                    return true;
        return false;
	}

	boolean poison_melee(){
        for (Item item : all_carried())
            if (item!=null)
                if (item.poison_melee())
                    return true;
        return false;
	}

	boolean dragon_slaying_melee(){
        for (Item item : all_carried())
            if (item!=null)
                if (item.dragon_slaying_melee())
                    return true;
        return false;
	}

	boolean undead_slaying_melee(){
        for (Item item : all_carried())
            if (item!=null)
                if (item.undead_slaying_melee())
                    return true;
        return false;
	}

	boolean magebane_missile(){
        for (Item item : all_carried())
            if (item!=null)
                if (item.magebane_missile())
                    return true;
        return false;
	}

	boolean fire_missile(){
        for (Item item : all_carried())
            if (item!=null)
                if (item.fire_missile())
                    return true;
        return false;
	}

	boolean poison_missile(){
        for (Item item : all_carried())
            if (item!=null)
                if (item.poison_missile())
                    return true;
        return false;
	}

	ArrayList<Item> all_carried(){
		ArrayList<Item> l = new ArrayList<Item>();
		l.add(armor);
		l.add(offhand);
		l.add(melee_weapon);
		l.add(missile_weapon);
		if (trinkets.size()>0)
			l.add(trinkets.get(0));
		if (trinkets.size()>1)
			l.add(trinkets.get(1));
		if (trinkets.size()>2)
			l.add(trinkets.get(2));
		if (trinkets.size()>3)
			l.add(trinkets.get(3));
  		return l;
	}

	int get_aggro(){
		int x = 0;
        for (Item item : all_carried())
            if (item!=null)
            	x = x + item.aggro();
        return x;
	}

	int get_basic_strength(){
		int x;
        if (class_code==Class_code.C_WARRIOR){
            x = stat1;
        } else {
            x = 2;
        }
        return x;
	}

	int get_basic_skill(){
		int x;
        if (class_code==Class_code.C_WARRIOR){
            x = stat2;
        } else {
            x = 2;
        }
        return x;
	}

	int get_basic_daring(){
		int x;
        if (class_code==Class_code.C_ROGUE){
            x = stat1;
        } else {
            x = 2;
        }
        return x;
	}

	int get_basic_cunning(){
		int x;
        if (class_code==Class_code.C_ROGUE){
            x = stat2;
        } else {
            x = 2;
        }
        return x;
	}

	int get_basic_power(){
		int x;
        if (class_code==Class_code.C_MAGE){
            x = stat1;
        } else {
            x = 2;
        }
        return x;
	}

	int get_basic_subtlety(){
		int x;
        if (class_code==Class_code.C_MAGE){
            x = stat2;
        } else {
            x = 2;
        }
        return x;
	}

	int get_basic_valor(){
		int x;
        if (class_code==Class_code.C_PRIEST){
            x = stat1;
        } else {
            x = 2;
        }
        return x;
	}

	int get_basic_wisdom(){
		int x;
        if (class_code==Class_code.C_PRIEST){
            x = stat2;
        } else {
            x = 2;
        }
        return x;
	}

	int get_strength(){
		int x;
        if (class_code==Class_code.C_WARRIOR){
            x = stat1;
        } else {
            x = 2;
        }
        for (Item item : all_carried())
            if (item!=null)
            	x = x + item.strength();
        return x;
	}

	int get_skill(){
		int x;
        if (class_code==Class_code.C_WARRIOR){
            x = stat2;
        } else {
            x = 2;
        }
        for (Item item : all_carried())
            if (item!=null)
            	x = x + item.skill();
        return x;
	}

	int get_daring(){
		int x;
        if (class_code==Class_code.C_ROGUE){
            x = stat1;
        } else {
            x = 2;
        }
        for (Item item : all_carried())
            if (item!=null)
            	x = x + item.daring();
        return x;
	}

	int get_cunning(){
		int x;
        if (class_code==Class_code.C_ROGUE){
            x = stat2;
        } else {
            x = 2;
        }
        for (Item item : all_carried())
            if (item!=null)
            	x = x + item.cunning();
        return x;
	}

	int get_power(){
		int x;
        if (class_code==Class_code.C_MAGE){
            x = stat1;
        } else {
            x = 2;
        }
        for (Item item : all_carried())
            if (item!=null)
            	x = x + item.power();
        return x;
	}

	int get_subtlety(){
		int x;
        if (class_code==Class_code.C_MAGE){
            x = stat2;
        } else {
            x = 2;
        }
        for (Item item : all_carried())
            if (item!=null)
            	x = x + item.subtlety();
        return x;
	}

	int get_valor(){
		int x;
        if (class_code==Class_code.C_PRIEST){
            x = stat1;
        } else {
            x = 2;
        }
        for (Item item : all_carried())
            if (item!=null)
            	x = x + item.valor();
        return x;
	}

	int get_wisdom(){
		int x;
        if (class_code==Class_code.C_PRIEST){
            x = stat2;
        } else {
            x = 2;
        }
        for (Item item : all_carried())
            if (item!=null)
            	x = x + item.wisdom();
        return x;
	}

	int get_constitution(){
        int x = constitution;
        for (Item item : all_carried())
            if (item!=null)
            	x = x + item.constitution();
        return x;
	}

	int get_reflexes(){
        int x = reflexes;
        for (Item item : all_carried())
            if (item!=null)
            	x = x + item.reflexes();
        return x;
	}

	int get_stamina(){
        int x = stamina;
        for (Item item : all_carried())
            if (item!=null)
            	x = x + item.stamina();
        return x;
	}

	int get_speed(){
        int stat, x;
        if (class_code==Class_code.C_WARRIOR){
            stat = get_skill();
        } else if (class_code==Class_code.C_ROGUE){
            stat = get_daring();
        } else {
            stat = 2;
        }
        List<Integer> progression = null;
        if (stat<=1){
        	progression = new ArrayList<Integer>();
        } else if (stat==2){
        	progression = new ArrayList<Integer>();
        } else if (stat==3){
        	progression = make_progression(0,3,5,5);
        } else if (stat==4){
        	progression = make_progression(0,2,4,4);
        } else if (stat==5){
        	progression = make_progression(0,1,3,3);
        } else if (stat==6){
        	progression = make_progression(0,1,2,3);
        } else if (stat==7){
        	progression = make_progression(0,1,2,2);
        } else if (stat>=8){
        	progression = make_progression(0,1,2,1);
        }
        x = value(level,progression);
        for (Item item : all_carried())
            if (item!=null)
            	x = x + item.speed();
        return x;
	}

	int get_damage(){
		int stat, x=-1;
        if (class_code==Class_code.C_WARRIOR){
            stat = get_strength();
        } else if (class_code==Class_code.C_PRIEST){
        	stat = get_valor();
		} else {
            stat = 2;
        }
        if (stat<=1){
            x = -3;
        } else if (stat==2){
            x = 0;
        } else if (stat==3){
            x = 2;
        } else if (stat==4){
            x = 4;
        } else if (stat==5){
            x = 6;
        } else if (stat==6){
            x = 8;
        } else if (stat==7){
            x = 10;
        } else if (stat>=8){
            x = 12;
        }
        for (Item item : all_carried())
            if (item!=null)
            	x = x + item.damage();
        return x;
	}

	int get_accuracy(){
        int stat, x=-1;
        if (class_code==Class_code.C_WARRIOR){
            stat = get_skill();
        } else if (class_code==Class_code.C_ROGUE){
            stat = get_daring();
        } else {
            stat = 2;
        }
        List<Integer> progression = null;
        if (stat<=1){
        	progression = make_progression(0,5,4,4);
        } else if (stat==2){
        	progression = make_progression(0,3,2,2);
        } else if (stat==3){
        	progression = make_progression(0,2,1,2);
        } else if (stat==4){
        	progression = make_progression(0,1,2,1);
        } else if (stat==5){
        	progression = make_progression(0,1,1,2);
        } else if (stat==6){
        	progression = make_progression(0,1,1,1);
        } else if (stat==7){
        	progression = Arrays.asList(1,2,2,3,4,5,5,6,7,8,8,9,10,11,11,12,13,14,14,15,16,17,17,18,19,20,20);
        } else if (stat>=8){
        	progression = Arrays.asList(1,2,2,3,4,4,5,6,6,7,8,8,9,10,10,11,12,12,13,14,14,15,16,16,17,18,18,19);
        }
        x = value(level,progression);
        for (Item item : all_carried())
            if (item!=null)
            	x = x + item.accuracy();
        return x;
	}

	int get_rapidity(){
        int stat, x=-1;
        if (class_code==Class_code.C_ROGUE){
            stat = get_daring();
        } else {
            stat = 2;
        }
        List<Integer> progression = null;
        if (stat<=1){
        	progression = new ArrayList<Integer>();
        } else if (stat==2){
        	progression = new ArrayList<Integer>();
        } else if (stat==3){
        	progression = make_progression(0,3,5,5);
        } else if (stat==4){
        	progression = make_progression(0,2,4,4);
        } else if (stat==5){
        	progression = make_progression(0,1,3,3);
        } else if (stat==6){
        	progression = make_progression(0,1,2,3);
        } else if (stat==7){
        	progression = make_progression(0,1,2,2);
        } else if (stat>=8){
        	progression = make_progression(0,1,2,1);
        }
        x = value(level,progression);
        for (Item item : all_carried())
            if (item!=null)
            	x = x + item.rapidity();
        return x;
	}

	int get_penetration(){
		int stat, x=-1;
        if (class_code==Class_code.C_MAGE){
            stat = get_power();
        } else {
            stat = 2;
        }
        if (stat<=1){
            x = -3;
        } else if (stat==2){
            x = 0;
        } else if (stat==3){
            x = 2;
        } else if (stat==4){
            x = 4;
        } else if (stat==5){
            x = 6;
        } else if (stat==6){
            x = 8;
        } else if (stat==7){
            x = 10;
        } else if (stat>=8){
            x = 12;
        }
        for (Item item : all_carried())
            if (item!=null)
            	x = x + item.penetration();
        return x;
	}

	int get_aim(){
		int stat, x=-1;
        if (class_code==Class_code.C_MAGE){
            stat = get_subtlety();
        } else if (class_code==Class_code.C_ROGUE){
            stat = get_daring();
        } else {
            stat = 2;
        }
        List<Integer> progression = null;
        if (stat<=1){
        	progression = make_progression(0,5,4,4);
        } else if (stat==2){
        	progression = make_progression(0,3,2,2);
        } else if (stat==3){
        	progression = make_progression(0,2,1,2);
        } else if (stat==4){
        	progression = make_progression(0,1,2,1);
        } else if (stat==5){
        	progression = make_progression(0,1,1,2);
        } else if (stat==6){
        	progression = make_progression(0,1,1,1);
        } else if (stat==7){
        	progression = Arrays.asList(1,2,2,3,4,5,5,6,7,8,8,9,10,11,11,12,13,14,14,15,16,17,17,18,19,20,20);
        } else if (stat>=8){
        	progression = Arrays.asList(1,2,2,3,4,4,5,6,6,7,8,8,9,10,10,11,12,12,13,14,14,15,16,16,17,18,18,19);
        }
        x = value(level,progression);
        for (Item item : all_carried())
            if (item!=null)
            	x = x + item.aim();
        return x;
	}

	int get_evasion(){
        int stat, x=-1;
        if (class_code==Class_code.C_WARRIOR){
            stat = get_skill();
        } else if (class_code==Class_code.C_ROGUE){
            stat = get_daring();
        } else {
            stat = 2;
        }
        List<Integer> progression = null;
        if (stat<=1){
        	progression = new ArrayList<Integer>();
        } else if (stat==2){
        	progression = make_progression(0,5,5,5);
        } else if (stat==3){
        	progression = make_progression(0,4,4,4);
        } else if (stat==4){
        	progression = make_progression(0,3,3,3);
        } else if (stat==5){
        	progression = make_progression(0,2,3,2);
        } else if (stat==6){
        	progression = make_progression(0,1,2,2);
        } else if (stat>=7){
        	progression = make_progression(0,1,1,2);
        }
        x = value(level,progression);
        for (Item item : all_carried())
            if (item!=null)
            	x = x + item.evasion();
        return x;
	}

	int get_armor(){
		int x = 0;
        for (Item item : all_carried())
            if (item!=null)
            	x = x + item.armor();
        return x;
	}

    int get_n_skills(){
        int stat = intelligence;
        List<Integer> progression = null;
        if (stat<=1){
            progression = make_progression(0,1,2,2);
        } else if (stat==2){
            progression = make_progression(0,1,1,2);
        } else if (stat==3){
            progression = make_progression(0,1,1,1);
        } else if (stat==4){
            progression = Arrays.asList(1,1,2,3,4,5,5,6,7,8,9,9,10,11,11,12,13,13,14,15,15,16,17,17,18,19,19,20);
        } else if (stat==5){
            progression = Arrays.asList(1,1,2,3,3,4,5,5,6,7,7,8,9,9,10,11,11,12,13,13,14,15,15,16,17,17,18,19,19,20);
        } else if (stat==6){
            progression = Arrays.asList(1,1,2,2,3,4,4,5,5,6,7,7,8,8,9,10,10,11,11,12,13,13,14,14,15,16,16,17,17,18,19,19,20,20);
        } else if (stat==7){
            progression = make_progression(2,1,1,0);
        }
        return value(level,progression);
    }

    boolean can_use(Item item){
        if (!item.class_codes().contains(class_code))
        	return false;
        if (item.is_missile_weapon() && !master_action_codes.contains(Character_action_code.CA_SHOOT) && class_code==Class_code.C_WARRIOR)
        	return false;
        if (item.is_missile_weapon() && item.takes_arrows() && master_action_codes.contains(Character_action_code.CA_ZEN_ARCHER))
        	return true;
        if (item.is_missile_weapon() && !master_action_codes.contains(Character_action_code.CA_SLING) && class_code==Class_code.C_PRIEST)
        	return false;
        if (item.has_stat_requirement()){
            if (item.requires_strength()!=null)
                if (item.requires_strength() <= get_basic_strength())
                    return true;
            if (item.requires_skill()!=null)
                if (item.requires_skill() <= get_basic_skill())
                    return true;
            if (item.requires_daring()!=null)
                if (item.requires_daring() <= get_basic_daring())
                    return true;
            if (item.requires_valor()!=null)
                if (item.requires_valor() <= get_basic_valor())
                    return true;
            if (item.requires_subtlety()!=null)
                if (item.requires_subtlety() <= get_basic_subtlety())
                    return true;
            if (item.requires_power()!=null)
                if (item.requires_power() <= get_basic_power())
                    return true;
            if (item.requires_cunning()!=null)
                if (item.requires_cunning() <= get_basic_cunning())
                    return true;
            if (item.requires_wisdom()!=null)
                if (item.requires_wisdom() <= get_basic_wisdom())
                    return true;
            return false;
        }
        return true;
    }

    boolean meets_requirements(Character_action_code ac){
    	Character_action a = Campaignstate.ca.make_action(ac);
    	if (a==null) return false;
    	boolean any_ok=false, any_not_ok=false;
    	if (this.class_code==Class_code.C_WARRIOR && a.requires_strength()>0){
    		if (a.requires_strength()<=stat1)
    			any_ok = true;
    		else
    			any_not_ok = true;
    	}
    	if (this.class_code==Class_code.C_WARRIOR && a.requires_skill()>0){
    		if (a.requires_skill()<=stat2)
    			any_ok = true;
    		else
    			any_not_ok = true;
    	}
    	if (this.class_code==Class_code.C_PRIEST && a.requires_valor()>0){
    		if (a.requires_valor()<=stat1)
    			any_ok = true;
    		else
    			any_not_ok = true;
    	}
    	if (this.class_code==Class_code.C_PRIEST && a.requires_wisdom()>0){
    		if (a.requires_wisdom()<=stat2)
    			any_ok = true;
    		else
    			any_not_ok = true;
    	}
    	if (this.class_code==Class_code.C_ROGUE && a.requires_daring()>0){
    		if (a.requires_daring()<=stat1)
    			any_ok = true;
    		else
    			any_not_ok = true;
    	}
    	if (this.class_code==Class_code.C_ROGUE && a.requires_cunning()>0){
    		if (a.requires_cunning()<=stat2)
    			any_ok = true;
    		else
    			any_not_ok = true;
    	}
    	if (this.class_code==Class_code.C_MAGE && a.requires_power()>0){
    		if (a.requires_power()<=stat1)
    			any_ok = true;
    		else
    			any_not_ok = true;
    	}
    	if (this.class_code==Class_code.C_MAGE && a.requires_subtlety()>0){
    		if (a.requires_subtlety()<=stat2)
    			any_ok = true;
    		else
    			any_not_ok = true;
    	}
    	if (a.requires_constitution()>0){
    		if (a.requires_constitution()<=constitution)
    			any_ok = true;
    		else
    			any_not_ok = true;
    	}
    	if (a.requires_reflexes()>0){
    		if (a.requires_reflexes()<=reflexes)
    			any_ok = true;
    		else
    			any_not_ok = true;
    	}
    	if (a.requires_stamina()>0){
    		if (a.requires_stamina()<=stamina)
    			any_ok = true;
    		else
    			any_not_ok = true;
    	}
    	if (a.requires_training()>0){
    		if (a.requires_training()<=intelligence)
    			any_ok = true;
    		else
    			any_not_ok = true;
    	}
    	if (any_not_ok && !any_ok)
    		return false;
    	if (a.requires_level()>level){
			if (!(master_action_codes.contains(Character_action_code.CA_PRECOCIOUS) && a.requires_level()==level+1))
    			return false;
		}
    	for (Character_action_code ac2 : master_action_codes){
    		Character_action a2 = Campaignstate.ca.make_action(ac2);
    		if (a2.prevents().contains(ac))
    			return false;
    	}
    	if (a.prerequisites().size()>0){
    		boolean ok = false;
    		for (Character_action_code ac3 : master_action_codes){
    			if (a.prerequisites().contains(ac3))
    				ok = true;
    		}
    		for (Character_action_code ac3 : obsoleted_actions){
    			if (a.prerequisites().contains(ac3))
    				ok = true;
    		}
    		if (!ok)
    			return false;
    	}
    	if (class_code==Class_code.C_PRIEST && !a.priest_ok())
    		return false;
    	if (class_code==Class_code.C_MAGE && !a.mage_ok())
    		return false;
    	if (class_code==Class_code.C_WARRIOR && !a.warrior_ok())
    		return false;
    	if (class_code==Class_code.C_ROGUE && !a.rogue_ok())
    		return false;
    	for (Character_action_code ac4 : master_action_codes){
    		if (ac4==ac)
    			return false;
    	}
    	for (Character_action_code ac5 : obsoleted_actions){
    		if (ac5==ac)
    			return false;
    	}
    	return true;
    }

}